{
 "cells": [
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "# grpc-jsts",
   "id": "af1280add065c63f"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": [
    "## 安装必要的grpc工具包  \n",
    "npm install ts-protoc-gen grpc-tools --save-dev  \n",
    "npm install @grpc/grpc-js"
   ],
   "id": "49327f0fcbfaecb9"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": [
    "## 可选工具包\n",
    "如果电脑没有ts的运行环境,可以安装ts-node用来执行ts文件  \n",
    "npm install -g ts-node  \n",
    "例如执行ts客户端,在cmd进入src/client后,使用以下指令执行ts:  \n",
    "ts-node index.ts"
   ],
   "id": "bbff2e62078abcfe"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": [
    "## 本测试用例使用grpc版本:  \n",
    "grpc: 1.38.0-dev  \n",
    "protoc: 3.15.2  \n",
    "二进制包链接：https://pan.baidu.com/s/13E6bFcpFNYyhWgfBXxInOQ?pwd=wbga \n",
    "\n",
    "\n",
    "需要安装grpc版本小于20.1,高于此版本后,生成js会报错('protoc-gen-js' 不是内部或外部命令，也不是可运行的程序)  \n",
    "参考链接: https://stackoverflow.com/questions/72572040/protoc-gen-js-program-not-found-or-is-not-executable  \n",
    "\n",
    "安装完成的grpc需要暴露到环境变量中  "
   ],
   "id": "dd7e28fc486ec51b"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": [
    "## 这里有多种方式用来生成ts文件\n",
    "proto生成操作都在src/proto下  \n",
    "执行gen.py可以直接在proto同目录下生成,gen.cmd是windows平台的(这里需要注意的是,里面标识的路径需要使用绝对路径),linux的gen.sh未测试"
   ],
   "id": "7b40c702631bdf1b"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": [
    "### python执行gen.py\n",
    "参见src/proto/gen.py:\n",
    "```python\n",
    "import os.path\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    # 获得当前路径\n",
    "    curPath = os.path.abspath('.')\n",
    "    # 将路径定位到根路径下的node_modules\n",
    "    modulesPath = os.path.join(curPath, '..', '..', 'node_modules', '.bin')\n",
    "    modulesPath = os.path.abspath(modulesPath)\n",
    "    # 拼接\n",
    "    PROTOC_GEN_TS_PATH = os.path.join(modulesPath, \"protoc-gen-ts.cmd\")\n",
    "    PROTOC_GEN_GRPC_PATH = os.path.join(modulesPath, \"grpc_tools_node_protoc_plugin.cmd\")\n",
    "\n",
    "    # 输出路径\n",
    "    OUT_DIR = '.'\n",
    "\n",
    "    genCmd = (f'protoc '\n",
    "              f'--plugin=protoc-gen-ts=\"{PROTOC_GEN_TS_PATH}\" '\n",
    "              f'--plugin=protoc-gen-grpc=\"{PROTOC_GEN_GRPC_PATH}\" '\n",
    "              f'--js_out=import_style=commonjs,binary:\"{OUT_DIR}\" '\n",
    "              f'--ts_out=service=grpc-node,mode=grpc-js:\"{OUT_DIR}\" '\n",
    "              f'--grpc_out=grpc_js:\"{OUT_DIR}\" '\n",
    "              f'hello.proto'\n",
    "              )\n",
    "\n",
    "    os.system(genCmd)\n",
    "\n",
    "```"
   ],
   "id": "ccb5b11120a7a19c"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": [
    "### windows执行的cmd指令\n",
    "参见src/proto/gen.cmd:\n",
    "```shell\n",
    ":: 插件路径声明,需要绝对路径\n",
    "set PROTOC_GEN_TS_PATH=\"E:/Practice/gRPC/grpc-jsts/node_modules/.bin/protoc-gen-ts.cmd\"\n",
    "set PROTOC_GEN_GRPC_PATH=\"E:/Practice/gRPC/grpc-jsts/node_modules/.bin/grpc_tools_node_protoc_plugin.cmd\"\n",
    "\n",
    ":: 输出路径(.js and .d.ts files),可以是相对路径\n",
    "set OUT_DIR=\".\"\n",
    "\n",
    "\n",
    "protoc ^\n",
    "    --plugin=protoc-gen-ts=\"%PROTOC_GEN_TS_PATH%\" ^\n",
    "    --plugin=protoc-gen-grpc=\"%PROTOC_GEN_GRPC_PATH%\" ^\n",
    "    --js_out=import_style=commonjs,binary:\"%OUT_DIR%\" ^\n",
    "    --ts_out=service=grpc-node,mode=grpc-js:\"%OUT_DIR%\" ^\n",
    "    --grpc_out=grpc_js:\"%OUT_DIR%\" ^\n",
    "    hello.proto\n",
    "\n",
    "```"
   ],
   "id": "3ea30d1082441832"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": [
    "执行完后在当前目录(脚本所在)下生成如下文件:  \n",
    "├── hello_grpc_pb.d.ts # grpc 相关  \n",
    "├── hello_grpc_pb.js # grpc 相关  \n",
    "├── hello_pb.d.ts # 消息相关  \n",
    "└── hello_pb.js # 消息相关"
   ],
   "id": "6c60dc79ffb81917"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": [
    "## 执行测试用例\n",
    "客户端测试文件:  \n",
    "src/client/index.ts\n",
    "\n",
    "服务端测试文件,以下两个都可以,区别在于编写的方式不一样,object直接以对象进行编写,index.ts则是类继承,测试使用object.ts:  \n",
    "src/server/object.ts  \n",
    "src/server/index.ts\n",
    "\n",
    "1、启动服务端:  \n",
    "cmd进入src/server目录,然后执行指令(有ide运行环境的直接执行object.ts即可):  \n",
    "ts-node object.ts\n",
    "\n",
    "2、启动客户端:\n",
    "cmd进入src/client目录,然后执行指令(有ide运行环境的直接执行index.ts即可):  \n",
    "ts-node index.ts\n"
   ],
   "id": "da3efa6f4633da23"
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
